import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:get/get.dart';
import 'package:sports_new/utils/date_time_utils.dart';
import 'package:sports_new/utils/utils.dart';
import 'package:sports_new/view/my/socket_page.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/status.dart' as status;
import '../../utils/sp_utils.dart';
import '../../utils/user.dart';

typedef WsEvent = Map<String, dynamic>;

enum WsStatus { connected, disconnected, error }

class WebSocketManager {
  static final StreamController<WsEvent> _messageStreamController =
      StreamController<WsEvent>.broadcast();
  IOWebSocketChannel? _webSocketChannel;
  static WsStatus wsStatus = WsStatus.disconnected;
  Timer? _heartbeatTimer;
  static List<String> record = [];
  List<int> reconnectTime = [0, 10, 30, 60, 120];
  int reconnectCount = 0;
  static bool firstConnect = true;

  static get getUrl => () {
        final host = Uri.parse(SpUtils.baseUrl).host;
        final isProduction = host == 'api.qiukedao.net';
        return "${isProduction?'wss':'ws'}://$host${isProduction ? '' : ''}/websocket${User.auth?.userId.hasValue == true ? "?userId=${User.auth?.userId}" : ""}";
      }.call();

  void recordAdd(String value) {
    record.add(value);
    if (record.length >= 500) record.removeAt(0);
    try {
      Get.find<SocketTestController>().toEnd();
    } catch (e) {
      log(e.toString());
    }
  }

  static Stream<WsEvent> get messageStream => _messageStreamController.stream;

  void connect() {
    if (firstConnect) firstConnect = false;
    if (wsStatus == WsStatus.connected) return;
    log("webSocket 连接--------------");
    recordAdd("${DateTime.now().formatedString("HH:mm:ss.SSS")} webSocket 连接");
    _webSocketChannel = IOWebSocketChannel.connect(getUrl,
        headers: {"uuid": SpUtils.appUuid, "version": "1.0"});
    _webSocketChannel?.stream.listen(
      cancelOnError: true,
      (message) {
        if (reconnectCount != 0) reconnectCount = 0;
        final map = jsonDecode(message) as Map<String, dynamic>;
        _messageStreamController.add(map);
        recordAdd(
            "${DateTime.now().formatedString("HH:mm:ss.SSS")} 收到消息$message");
      },
      onError: (error) {
        log('WebSocket error: $error');
        recordAdd("${DateTime.now().formatedString("HH:mm:ss.SSS")} 遇到错误");
        wsStatus = WsStatus.error;
        reconnect();
      },
      onDone: () {
        log('WebSocket closed');
        recordAdd("${DateTime.now().formatedString("HH:mm:ss.SSS")} 连接关闭");
        wsStatus = WsStatus.disconnected;
        reconnect();
      },
    );
    wsStatus = WsStatus.connected;
    startHeartbeat();
  }

  void sendMessage(dynamic message) {
    if (wsStatus != WsStatus.connected) {
      log('WebSocket not connected');
      return;
    }
    _webSocketChannel?.sink.add(message);
  }

  void startHeartbeat() {
    if (wsStatus != WsStatus.connected) {
      return;
    }
    _heartbeatTimer = Timer.periodic(const Duration(seconds: 10), (timer) {
      sendMessage('heartbeat');
      recordAdd("${DateTime.now().formatedString("HH:mm:ss.SSS")} 心跳包发送");
      log("${DateTime.now()} 心跳包发送-------");
    });
  }

  void stopHeartbeat() {
    _heartbeatTimer?.cancel();
  }

  void reconnect() {
    if (reconnectCount > 5) {
      recordAdd("${DateTime.now().formatedString("HH:mm:ss.SSS")} 重连过多断开连接");
      close();
      return;
    }
    if (wsStatus == WsStatus.connected) {
      return;
    }
    log("webSocket 重连--------------");
    stopHeartbeat();
    Future.delayed(Duration(seconds: reconnectTime[reconnectCount]))
        .then((value) {
      recordAdd(
          "${DateTime.now().formatedString("HH:mm:ss.SSS")} 重新连接第$reconnectCount次");
      _webSocketChannel?.sink.close(status.normalClosure);
      _webSocketChannel = null;
      connect();
      reconnectCount++;
    });
  }

  void close() {
    stopHeartbeat();
    _webSocketChannel?.sink.close(status.goingAway);
    _messageStreamController.close();
  }
}
